// 期望用户使用该类的时候传入的是一个对象 new MyVue({data: {...}})
class MyVue {
  constructor(options) {
    this.$options = options // 对传入的对象进行缓存

    // 数据响应化操作
    this.$data = this.$options.data
    this.observe(this.$data) // 创建一个监听函数，对this.$data中的数据进行监听

    new Compile(options.el, this)

    // 生命后期函数 created执行
    if (options.created) {
      options.created.call(this)
    }
  }
  /**
   * 数据监听函数，会对传入的数据进行监听
   * @param {* 监听的数据} data 
   */
  observe(data) {
    // 判断数据是否传入，以及传入哦数据的格式是否正确
    if (!data || typeof data !== 'object') {
      throw new TypeError('without data or the typeof data is wrong')
    }
    Object.keys(data).forEach(key => {
      this.defineReactive(data, key, data[key]) // 定义一个函数，对数据进行响应化操作

      // 将$data中的数据代理到vue实例上
      this.proxyData(key)
    })
  }
  /**
   * 实现数据的响应化defineRaective
   * @param {* 要进行响应化操作的对象} data 
   * @param {* 对象中要进行响应化处理的属性} key 
   * @param {* 要进行响应化操作的属性值} value 
   */
  defineReactive(data, key, value) {
    // 如果当前的value是一个对象，则对其进行递归，拿到其内部的属性
    if (typeof value === 'object') {
      this.observe(value)
    }

    const dep = new Dep()

    Object.defineProperty(data, key, {
      get() {
        Dep.target && dep.addDep(Dep.target)
        return value
      },
      set(val) {
        if (val === value) { // 判断当前值于传入的值是否相等，如果不相等，对其进行更新
          return
        }
        value = val
        dep.notify()
        console.log(`${key}属性值被更新为${val}`)
      }
    })
  }

  // 将$data中的属性代理到vue实例中
  proxyData(key) {
    Object.defineProperty(this, key, {
      get() {
        return this.$data[key]
      },
      set(value) {
        this.$data[key] = value
      }
    })
  }
}
